home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / freeWAIS-sf-1.1 / ir / irfileio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  19.0 KB  |  826 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  9.  
  10.  
  11. /* Change log:
  12.  * $Log: irfileio.c,v $
  13.  * Revision 1.5  1994/09/07  13:29:22  pfeifer
  14.  * ctype is now included from cdialect.h after inclusion of string.h.
  15.  * Since ctype.h (the local version defines strcmp and friends, inclusion o
  16.  * of string.h after that caused probems
  17.  *
  18.  * Revision 1.4  1994/07/15  17:11:03  pfeifer
  19.  * negative numerics
  20.  *
  21.  * Revision 1.3  1994/05/20  12:56:05  pfeifer
  22.  * beta
  23.  *
  24.  * Revision 1.2  1994/03/08  21:06:19  pfeifer
  25.  * Patchlevel 04
  26.  *
  27.  * Revision 1.1  1993/02/16  15:05:35  freewais
  28.  * Initial revision
  29.  *
  30.  * Revision 1.12  92/04/12  17:30:21  jonathan
  31.  * Fixed WriteString to quote backslash as well as double-quotes.  Thanks to
  32.  * dxl0243@hertz.njit.edu (Dong Liu).
  33.  * 
  34.  * Revision 1.11  92/03/06  10:57:16  jonathan
  35.  * removed extraneous ; after function WriteTM.
  36.  * 
  37.  * Revision 1.10  92/03/04  19:20:33  jonathan
  38.  * Made SkipObject return EOF if at end of file.
  39.  * 
  40.  * Revision 1.9  92/02/16  21:08:37  jonathan
  41.  * Changed a few more char ch to long ch (for return value of fgetc).
  42.  * 
  43.  * Revision 1.8  92/02/12  13:24:13  jonathan
  44.  * Added "$Log" so RCS will put the log message in the header
  45.  * 
  46. */
  47.  
  48. /********************************************************
  49.  *  Writing and reading structures to files.        *
  50.  *                            *
  51.  *  These use the Lisp printer format with the        *
  52.  *  lisp naming conventions.  You ask: "Why would    *
  53.  *  you want to use that?".  Well, we need an        *
  54.  *  easily readable data syntax that can handle        *
  55.  *  a large number of different data types.        *
  56.  *  Further, we need it to be tagged so that        *
  57.  *  run time tagged languages can read it and         *
  58.  *  it is flexible.  We need one that supports        *
  59.  *  optional fields so that the format can         *
  60.  *  grow backcompatibly.  And (the kicker),        *
  61.  *  it must be read from many languages since        *
  62.  *  user interfaces may be written in anything        *
  63.  *  from smalltalk to hypercard.            *
  64.  *                             *
  65.  *  -brewster 5/10/90                    *
  66.  ********************************************************/
  67.  
  68. /*
  69. #include <string.h>
  70. */
  71. #include "irfileio.h"
  72. #include "cutil.h"
  73.  
  74. #define INDENT_SPACES 2
  75. #define MAX_INDENT 40
  76. static long indent_level;  /* this is the number of indent levels */
  77.  
  78.  
  79. /**********************/
  80. /*  WRITING TO FILES  */
  81. /**********************/
  82.  
  83.  
  84. static void indent _AP((FILE* file));
  85.  
  86. static void indent(file)
  87. FILE* file;
  88. /* indent the right number of spaces.  make sure that indent_level is 
  89.  * non-negative, and that it does not indent too much
  90.  */
  91. {
  92.   long i;
  93.   for(i = 0; i <= MINIMUM(MAX_INDENT, MAXIMUM(0L, indent_level * INDENT_SPACES)); i++){
  94.     putc(' ', file);
  95.   }
  96. }
  97.  
  98. long WriteStartOfList(file)
  99. FILE* file;
  100. {
  101.   indent_level++;
  102.   return(fprintf(file, " ( "));
  103. }
  104.  
  105. long WriteEndOfList(file)
  106. FILE* file;
  107. {
  108.   indent_level--;
  109.   return(fprintf(file, " ) "));
  110. }
  111.  
  112. long WriteStartOfStruct(name,file)
  113. char* name;
  114. FILE* file;
  115. {
  116.   indent_level++;
  117.   return(fprintf(file, " (:%s ", name));
  118. }
  119.  
  120. long WriteEndOfStruct(file)
  121. FILE* file;
  122. {
  123.   indent_level--;
  124.   return(fprintf(file, " ) "));
  125. }
  126.  
  127. long WriteSymbol(name,file)
  128. char* name;
  129. FILE* file;
  130. {
  131.   return(fprintf(file, " %s ", name));
  132. }
  133.  
  134. long WriteNewline(file)
  135. FILE* file;
  136. {
  137.   long return_value = fprintf(file, "\n");
  138.   indent(file);
  139.   return(return_value);
  140. }
  141.  
  142. long WriteLong(number,file)
  143. long number;
  144. FILE* file;
  145. {
  146.   return(fprintf(file, " %ld ", number));  
  147. }
  148.  
  149. long WriteDouble(number,file)
  150. double number;
  151. FILE* file;
  152. {
  153.   return(fprintf(file, " %f ", number));
  154. }
  155.  
  156. long WriteString(string,file)
  157. char* string;
  158. FILE* file;
  159. {
  160.   long i;
  161.   putc('\"', file);
  162.   for(i = 0; i < strlen(string); i++){
  163.     if(string[i] == '\\' || string[i] == '\"')
  164.       putc('\\', file);        /* quote the string quotes going into the file */
  165.     putc(string[i], file);
  166.   }
  167.   putc('\"', file);
  168.   return(1);
  169. }
  170.  
  171. long WriteAny(value,file)
  172. any* value;
  173. FILE* file;
  174. {
  175.   WriteStartOfStruct("any", file);
  176.   WriteSymbol(":size", file); WriteLong(value->size, file);
  177.   WriteSymbol(":bytes", file);
  178.   Write8BitArray(value->size, value->bytes, file);
  179.   return(WriteEndOfStruct(file));
  180. }
  181.  
  182. long Write8BitArray(length,array,file)
  183. long length;
  184. char* array;
  185. FILE* file;
  186. {
  187.   long i;
  188.   fprintf(file, " #( ");
  189.   for(i=0; i<length; i++){
  190.     WriteLong((long)array[i], file);
  191.   }
  192.   return(fprintf(file, " ) "));
  193. }
  194.  
  195. /* Writes a time object to a file */
  196. long WriteTM(atime,file)
  197. struct tm* atime;
  198. FILE* file;
  199. {
  200.   WriteStartOfStruct("tm", file);
  201.   WriteSymbol(":tm-sec", file); WriteLong(atime->tm_sec, file);
  202.   WriteSymbol(":tm-min", file); WriteLong(atime->tm_min, file);
  203.   WriteSymbol(":tm-hour", file); WriteLong(atime->tm_hour, file);
  204.   WriteSymbol(":tm-mday", file); WriteLong(atime->tm_mday, file);
  205.   WriteSymbol(":tm-mon", file); WriteLong(atime->tm_mon, file);
  206.   WriteNewline(file);
  207.   WriteSymbol(":tm-year", file); WriteLong(atime->tm_year, file);
  208.   WriteSymbol(":tm-wday", file); WriteLong(atime->tm_wday, file);
  209.   WriteNewline(file);
  210.   WriteSymbol(":tm-yday", file); WriteLong(atime->tm_yday, file);
  211.   WriteSymbol(":tm-isdst", file); WriteLong(atime->tm_isdst, file);
  212.   WriteEndOfStruct(file);
  213.   return(WriteNewline(file));
  214. }
  215.  
  216. Boolean  
  217. writeAbsoluteTime(atime,file)
  218. struct tm* atime;
  219. FILE* file;
  220. {
  221.   WriteStartOfStruct("absolute-time",file);
  222.   WriteNewline(file);
  223.   WriteSymbol(":year",file); WriteLong((long)atime->tm_year,file);
  224.   WriteNewline(file);
  225.   WriteSymbol(":month",file); WriteLong((long)atime->tm_mon,file);
  226.   WriteNewline(file);
  227.   WriteSymbol(":mday",file); WriteLong((long)atime->tm_mday,file);
  228.   WriteNewline(file);
  229.   WriteSymbol(":hour",file); WriteLong((long)atime->tm_hour,file);
  230.   WriteNewline(file);
  231.   WriteSymbol(":minute",file); WriteLong((long)atime->tm_min,file);
  232.   WriteNewline(file);
  233.   WriteSymbol(":second",file); WriteLong((long)atime->tm_sec,file);
  234.   WriteNewline(file);
  235.   return(WriteEndOfStruct(file));
  236. }
  237.  
  238.  
  239.  
  240.  
  241. /************************/
  242. /*  READING FROM FILES  */
  243. /************************/
  244.  
  245.  
  246. /* these are states of the parser */
  247. #define BEFORE 1
  248. #define DURING 2
  249. #define HASH 3
  250. #define S 4
  251. #define QUOTE 5
  252.  
  253. /* returns TRUE if it hits an '(' before hitting any non whitespace.
  254.    It has an added hack to detect NIL: it looks to make sure that it is nil,
  255.    and then ungetc's a \) on the stream so that the end-checkers will catch it.
  256.    Quack. */
  257. Boolean ReadStartOfList(file)
  258. FILE* file;
  259. {
  260.   long ch;
  261.   while(TRUE){
  262.     ch = getc(file);
  263.     if(ch == '(') 
  264.       return(TRUE);
  265.     if(!isspace(ch)){
  266.       /* check for NIL */
  267.       if(ch == 'N' || ch == 'n'){
  268.     ch = getc(file);
  269.     if(ch == 'I' || ch == 'i'){
  270.       ch = getc(file);
  271.       if(ch == 'L' || ch == 'l'){
  272.         ungetc(')', file);
  273.         return(TRUE);
  274.       }
  275.     }
  276.       }
  277.       return(FALSE); /* not NIL */
  278.     }
  279.   }
  280. }
  281.  
  282.  
  283. /* returns TRUE if it hits an ')' before hitting any non whitespace*/
  284. Boolean ReadEndOfList(file)
  285. FILE* file;
  286. {
  287.   long ch;
  288.   while(TRUE){
  289.     ch = getc(file);
  290.     if(ch == ')') 
  291.       return(TRUE);
  292.     if(!isspace(ch)) 
  293.       return(FALSE);
  294.   }
  295. }
  296.  
  297. #define STRING_ESC '\\'
  298.  
  299. long 
  300. SkipObject(file)
  301. FILE* file;
  302. /* read an object of unknown type out of the file.  We handle:
  303.       strings
  304.       longs, doubles, and symbols
  305.       structs, lists, and arrays
  306.    and anything composed of them (absolute time etc)
  307. */
  308. {
  309.   long ch;
  310.  
  311.   while (true)    
  312.     { ch = getc(file);
  313.       if (ch == EOF)
  314.     return (EOF); /* we are done */
  315.       else
  316.     { if (isspace(ch))
  317.         continue; /* skip this char */
  318.       else if (ch == '"') /* string */
  319.         { long escapeCount = 0;
  320.           while (true)
  321.         { ch = getc(file);
  322.           if (ch == EOF)
  323.             return (EOF);
  324.           else
  325.             { if (ch == STRING_ESC)
  326.             { escapeCount++;
  327.               escapeCount = escapeCount % 2;
  328.             }
  329.               if (ch == '"' && escapeCount == 0)
  330.             break; /* out of reading string */
  331.                     }
  332.         }
  333.           break; /* we are done */
  334.             }
  335.       else if (isnumchar(ch) || /* number */
  336.            (ch == ':')) /* symbol */
  337.         { while (!isspace(ch)) /* just read till there is white space */
  338.         { ch = getc(file);
  339.           if (ch == EOF)
  340.             return(EOF);
  341.         }
  342.           break; /* we are done */
  343.         }
  344.       else if ((ch == '#') || /* array */
  345.            (ch == '(')) /* struct or list */
  346.         { long parenCount = 1;
  347.           if (ch == '#')    
  348.         ch = getc(file); /* read in the '(' so we can think of it
  349.                     as a list */
  350.           while (parenCount > 0)
  351.         { ch = getc(file);
  352.           if (ch == EOF)
  353.             return(EOF);
  354.           else if (ch == '"')
  355.             { /* start of a string, it may contain parens, 
  356.              so we will have to skip it */
  357.               ungetc(ch,file);
  358.               SkipObject(file);
  359.             }
  360.           else if (ch == '(') /* entering a new structure */    
  361.             parenCount++;
  362.           else if (ch == ')') /* leaving a structure */
  363.             parenCount--;
  364.         }
  365.           break; /* we are done */
  366.         }
  367.     }
  368.     }
  369.  
  370.   return(true);
  371. }
  372.  
  373. long ReadLong(file,answer)
  374. FILE* file;
  375. long* answer;
  376. /* reads a long int a file returns true if successful, false otherwise */
  377. {
  378.   long ch;
  379.   long state = BEFORE;
  380.   boolean isNegative = false;
  381.   long count = 0;
  382.   
  383.   *answer = 0;
  384.   
  385.   while(TRUE){
  386.     ch = getc(file);
  387.     if (ch == EOF){
  388.       break;            /* we are done */
  389.     }
  390.     else if (isdigit(ch)){
  391.       if(state == BEFORE){
  392.     state = DURING;
  393.       }
  394.       count++;
  395.       if(count == 12){
  396.     /* then we have an error in the file, 32 bit numbers can not be more
  397.        than 10 digits long */
  398.     return(false);
  399.       }
  400.       *answer = *answer * 10 + (ch - '0');
  401.     }
  402.     else if (ch == '-') {
  403.       if (isNegative)
  404.     /* then we have an error since there should be only one - in a number */
  405.     return(false);
  406.       if (state == BEFORE) {
  407.     /* we are ok since the - must come before any digits */
  408.     isNegative = true;
  409.     state = DURING;
  410.       }
  411.       else {
  412.     ungetc(ch,file);
  413.     break;            /* we are done */
  414.       }
  415.     }
  416.     else if(ch == ')' && (state == DURING)){
  417.       ungetc(ch, file);
  418.       return(true);        /* we are done */
  419.     }
  420.     else if(!isspace(ch)){
  421.       /* then we have an error since it should be a digit or a space */
  422.       return(false);
  423.     }
  424.     /* we do not have an digit */
  425.     else if(state == DURING){
  426.       ungetc(ch, file);
  427.       break;            /* we are done */
  428.     }
  429.     /* otherwise we are still before the start */
  430.   }
  431.   
  432.   if (isNegative)
  433.     *answer *= -1;
  434.   return(true);
  435. }
  436.  
  437. long ReadDouble(file,answer)
  438. FILE* file;
  439. double* answer;
  440. {
  441.   /* XXX this routine needs to deal with negative numbers! */
  442.   long ch;
  443.   long state = BEFORE;
  444.   long count = 0;
  445.   long decimal_count = 0;
  446.   
  447.   *answer = 0.0;
  448.   
  449.   while(TRUE){    
  450.     ch = getc(file);
  451.     if (ch == EOF){
  452.       return(true);
  453.     }
  454.     else if (ch == '.'){
  455.       decimal_count ++;
  456.     }
  457.     else if (isdigit(ch)){
  458.       if(state == BEFORE){
  459.     state = DURING;
  460.       }
  461.       count++;
  462.       if(count == 12){
  463.     /* then we have an error in the file, 32 bit numbers can not be more
  464.        than 10 digits long */
  465.     return(false);
  466.       }
  467.       if (decimal_count == 0){
  468.     *answer = *answer * 10 + (ch - '0');
  469.       }
  470.       else{            /* then we are in the fraction part */
  471.     double fraction = (ch - '0');
  472.     long internal_count;
  473.     for(internal_count = 0; internal_count < decimal_count; 
  474.         internal_count++){
  475.       fraction = fraction / 10.0;
  476.     }
  477.     *answer = *answer + fraction;
  478.     decimal_count++;
  479.       }
  480.     }
  481.     else if(!isspace(ch)){
  482.       /* then we have an error since it should be a digit or a space */
  483.       return(false);
  484.     }
  485.     /* we do not have an digit */
  486.     else if(state == DURING){
  487.       ungetc(ch, file);
  488.       return(true);        /* we are done */
  489.     }
  490.     /* otherwise we are still before the start */
  491.   }
  492. }
  493.  
  494. static Boolean issymbolchar _AP((long ch));
  495.  
  496. static 
  497. Boolean issymbolchar(ch)
  498. long ch;
  499. /* reads a symbol from a file and put it in the string argument.
  500.  * The string_size argument is used to make sure the string is not 
  501.  * overflowed.
  502.  */
  503. {
  504.   return(!( isspace(ch) || ch == ')' || ch == '(' || ch == EOF));
  505. }
  506.  
  507. /* reads a symbol from a file */
  508. long ReadSymbol(string,file,string_size)
  509. char* string;
  510. FILE* file;
  511. long string_size;
  512. {
  513.   long ch;
  514.   long state = BEFORE;
  515.   long position = 0;
  516.   
  517.   while(TRUE){
  518.     ch = getc(file);
  519.     if((state == BEFORE) && (ch == ')'))
  520.       return(END_OF_STRUCT_OR_LIST);
  521.     if(issymbolchar((long)ch)){    /* we are in a symbol */
  522.       if(state == BEFORE)
  523.     state = DURING;
  524.       string[position] = ch;
  525.       position++;
  526.       if(position >= string_size){
  527.     string[string_size - 1] = '\0';
  528.     return(FALSE);
  529.       }
  530.     }
  531.     /* we do not have an symbol character. we are done */
  532.     else if((state == DURING) || ch == EOF){
  533.       if(ch != EOF) ungetc(ch, file);
  534.       string[position] = '\0';
  535.       return(TRUE);        /* we are done */
  536.     }
  537.     /* otherwise we are still before the start of the symbol */
  538.   }
  539. }
  540.  
  541. long ReadEndOfListOrStruct(file)
  542. FILE* file;
  543. {
  544.   long ch;
  545.   while(TRUE){
  546.     ch = getc(file);
  547.     if (EOF == ch) 
  548.       return(FALSE);
  549.     else if(')' == ch) 
  550.       return(TRUE);
  551.     else if(!isspace(ch)) 
  552.       return(FALSE);
  553.   }
  554. }
  555.  
  556. /* reads a string from a file */
  557. long ReadString(string,file,string_size)
  558. char* string;
  559. FILE* file;
  560. long string_size;
  561. {
  562.   long ch;
  563.   long state = BEFORE;
  564.   long position = 0;
  565.   string[0] = '\0';  /* initialize to nothing */
  566.   
  567.   while(TRUE){
  568.     ch = getc(file);
  569.     if((state == BEFORE) && (ch == '\"'))
  570.       state = DURING;
  571.     else if (EOF == ch){
  572.       string[position] = '\0';
  573.       return(FALSE);
  574.     }
  575.     else if ((state == BEFORE) && (ch == ')'))
  576.       return(END_OF_STRUCT_OR_LIST);
  577.     else if ((state == DURING) && (ch == '\\'))
  578.       state = QUOTE; /* do nothing */
  579.     else if ((state == DURING) && (ch == '"')){    
  580.       string[position] = '\0';
  581.       return(TRUE);
  582.     }
  583.     else if ((state == QUOTE) || (state == DURING)){
  584.             if(state == QUOTE)
  585.                 state = DURING;
  586.             string[position] = ch;
  587.             position++;
  588.             if(position >= string_size){
  589.                 string[string_size - 1] = '\0';
  590.                 return(FALSE);
  591.             }
  592.         }
  593.         /* otherwise we are still before the start of the string */
  594.     }
  595. }
  596.  
  597. /* returns TRUE if it is the start of a struct
  598.  * returns END_OF_STRUCT_OR_LIST if it is a ')'
  599.  * returns FALSE if it is something unexpected
  600.  */
  601. long ReadStartOfStruct(name,file)
  602. char* name;
  603. FILE* file;
  604. {
  605.   long ch;
  606.   long state = BEFORE;
  607.     
  608.   name[0] = '\0';
  609.     
  610.   while(TRUE){
  611.     ch = getc(file);
  612.     if((state == BEFORE) && (ch == '#'))
  613.       state = HASH;
  614.     if((state == BEFORE) && (ch == '('))
  615.       state = DURING;
  616.     else if((state == BEFORE) && (ch == ')'))
  617.       return(END_OF_STRUCT_OR_LIST);
  618.     else if((state == BEFORE) && !isspace(ch))
  619.       return(FALSE);        /* we have a problem */
  620.     else if(state == HASH){
  621.       if (ch == 's')
  622.     state = S;
  623.       else{
  624.     fprintf(stderr,"Expected an 's' but got an %c\n", ch);
  625.     return(FALSE);
  626.       }
  627.     }
  628.     else if(state == S){
  629.       if (ch == '(')
  630.     state = DURING;
  631.       else{
  632.     fprintf(stderr,"Expected an '(' but got an an %c\n",ch);
  633.     return(FALSE);
  634.       }
  635.     }
  636.     else if(state == DURING){
  637.       return(ReadSymbol(name, file, MAX_SYMBOL_SIZE));
  638.     }
  639.   }
  640. }
  641.  
  642. /* returns TRUE if it is the right start of a struct,
  643.  * returns END_OF_STRUCT_OR_LIST if it is the end of a list,
  644.  * returns FALSE if it is something weird
  645.  */
  646. long CheckStartOfStruct(name,file)
  647. char* name;
  648. FILE* file;
  649. {
  650.   char temp_string[MAX_SYMBOL_SIZE];
  651.   long result = ReadStartOfStruct(temp_string, file);
  652.   if(result == END_OF_STRUCT_OR_LIST)
  653.     return(END_OF_STRUCT_OR_LIST);
  654.   else if(result == FALSE)
  655.     return(FALSE);
  656.   else if(0 == strcmp(temp_string, name))
  657.     return(TRUE);
  658.   else 
  659.     return(FALSE);
  660. }
  661.  
  662. /* reads an any.  an any with no bytes allocated.  The right number of bytes
  663.  * will be malloc'ed while reading
  664.  */
  665. long ReadAny(destination,file)
  666. any* destination;
  667. FILE* file;
  668. {
  669.   char temp_string[MAX_SYMBOL_SIZE];
  670.     
  671.   destination->size = 0; /* initialize so that if an error happens 
  672.                 it does not blow up */
  673.   if(FALSE == CheckStartOfStruct("any", file)){
  674.     fprintf(stderr,"An 'any' structure was not read from the disk");
  675.     return(FALSE);
  676.   }
  677.     
  678.   while(TRUE){
  679.     long check_result;
  680.     check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
  681.     if(FALSE == check_result) 
  682.       return(FALSE);
  683.     if(END_OF_STRUCT_OR_LIST == check_result) 
  684.       return(TRUE);
  685.         
  686.     if(0 == strcmp(temp_string, ":size")) {
  687.       long    size;
  688.       ReadLong(file,&size);
  689.       destination->size = (unsigned long)size;
  690.     }
  691.     else if(0 == strcmp(temp_string, ":bytes")){
  692.       long result;
  693.       /* the size must have been read in by now */
  694.       destination->bytes = (char*)s_malloc(destination->size);
  695.       if(NULL == destination->bytes){
  696.     fprintf(stderr,
  697.         "Error on reading file. Malloc ran out of memory in an ANY");
  698.     return(FALSE);
  699.       }
  700.       result = Read8BitArray(destination->bytes, file, destination->size);
  701.       if(FALSE == result)
  702.     return(FALSE);
  703.     }
  704.     else{
  705.       fprintf(stderr,"Unknown keyword for ANY %s\n", temp_string);
  706.       return(FALSE);
  707.     }
  708.   }
  709. }
  710.  
  711. /* this does not need the length, but it will probably know it in all cases */
  712. long Read8BitArray(destination,file,length)
  713. char* destination;
  714. FILE* file;
  715. long length;
  716. {
  717.   /* arrays start with #( */
  718.   long ch;
  719.   long state = BEFORE;
  720.   while(TRUE){
  721.     ch = getc(file);
  722.     if((state == BEFORE) && ((ch == '#') || (ch == '('))) {
  723.       if (ch == '(') state = DURING;
  724.       else state = HASH;
  725.     }
  726.     else if((state == BEFORE) && !isspace(ch)){
  727.       fprintf(stderr,"error in reading array.  Expected # and got %c", ch);
  728.       return(FALSE);
  729.     }
  730.     else if(state == HASH){
  731.       if (ch == '(')
  732.     state = DURING;
  733.       else{
  734.     fprintf(stderr,"Expected an '(' but got an %c\n", ch);
  735.     return(FALSE);
  736.       }
  737.     }
  738.     else if(state == DURING){
  739.       long i;
  740.       ungetc(ch, file);
  741.       for(i = 0; i < length; i++){
  742.     long value;
  743.     if(ReadLong(file,&value) == false){ /* then it error'ed */
  744.       fprintf(stderr,"Error in reading a number from the file.");
  745.       return(FALSE);
  746.     }
  747.     if(value > 255){    /* then we have read a non-char */
  748.       fprintf(stderr,"Error in reading file.  Expected a byte in an ANY, but got %ld", value);
  749.       return(FALSE);
  750.     }
  751.     destination[i] = (char)value;
  752.       }
  753.       if(FALSE == ReadEndOfListOrStruct(file)){
  754.     fprintf(stderr,"array was wrong length");
  755.     return(FALSE);
  756.       }
  757.       return(TRUE);
  758.     }
  759.   }
  760. }
  761.             
  762.  
  763. Boolean
  764. readAbsoluteTime(atime,file)
  765. struct tm* atime;
  766. FILE* file;
  767. {
  768.   if (CheckStartOfStruct("absolute-time",file) == FALSE)
  769.     return(false);
  770.           
  771.   while (true)
  772.     { long result;
  773.       long val;
  774.       char temp_string[MAX_SYMBOL_SIZE + 1];
  775.      
  776.       result = ReadSymbol(temp_string,file,MAX_SYMBOL_SIZE);
  777.      
  778.       if (result == END_OF_STRUCT_OR_LIST)
  779.     break;
  780.       else if (result == false)
  781.     return(false);
  782.                   
  783.       if (strcmp(temp_string,":second") == 0)
  784.     { if (ReadLong(file,&val) == false)
  785.         return(false);
  786.       atime->tm_sec = val;
  787.     }
  788.  
  789.       else if (strcmp(temp_string,":minute") == 0)
  790.     { if (ReadLong(file,&val) == false)
  791.         return(false);
  792.       atime->tm_min = val;
  793.     }
  794.  
  795.       else if (strcmp(temp_string,":hour") == 0)
  796.     { if (ReadLong(file,&val) == false)
  797.         return(false);
  798.       atime->tm_hour = val;
  799.     }
  800.  
  801.       else if (strcmp(temp_string,":mday") == 0)
  802.     { if (ReadLong(file,&val) == false)
  803.         return(false);
  804.       atime->tm_mday = val;
  805.     }
  806.  
  807.       else if (strcmp(temp_string,":month") == 0)
  808.     { if (ReadLong(file,&val) == false)
  809.         return(false);
  810.       atime->tm_mon = val;
  811.     }
  812.  
  813.       else if (strcmp(temp_string,":year") == 0)
  814.     { if (ReadLong(file,&val) == false)
  815.         return(false);
  816.       atime->tm_year = val;
  817.     }
  818.       
  819.       else
  820.     SkipObject(file);
  821.  
  822.     }
  823.  
  824.   return(true);
  825. }
  826.